/**********************************************************************
 *                                                                    *
 * tgt - Tiny Graphics Toolbox                                        *
 *                                                                    *
 * Copyright (C) 2006-2008 Visualization and Computer Graphics Group, *
 * Department of Computer Science, University of Muenster, Germany.   *
 * <http://viscg.uni-muenster.de>                                     *
 *                                                                    *
 * This file is part of the tgt library. This library is free         *
 * software; you can redistribute it and/or modify it under the terms *
 * of the GNU Lesser General Public License version 2.1 as published  *
 * by the Free Software Foundation.                                   *
 *                                                                    *
 * This library is distributed in the hope that it will be useful,    *
 * but WITHOUT ANY WARRANTY; without even the implied warranty of     *
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the       *
 * GNU Lesser General Public License for more details.                *
 *                                                                    *
 * You should have received a copy of the GNU Lesser General Public   *
 * License in the file "LICENSE.txt" along with this library.         *
 * If not, see <http://www.gnu.org/licenses/>.                        *
 *                                                                    *
 **********************************************************************/

#include <iostream>
#include <string>

#include <cmath>

#include "tgt/assert.h"
#include "tgt/types.h"
#include "tgt/math.h"
#include "tgt/vector.h"
#include "tgt/matrix.h"
#include "tgt/quaternion.h"
#include "tgt/line.h"
#include "tgt/plane.h"

using namespace tgt;

int main(int argc, char** argv) {
    std::cout
        << "tgt Sample Program: math" << std::endl
        << std::endl
        << "Demonstrates tgt's math and geometry capabilities. No graphical output here." << std::endl
        << std::endl;


    /*
        do funny matrix and vector stuff
    */
    float af[3] = {4.f, -5.f, 2.f};

    vec3 v1(2.f), v2(-2.f, 3.f, -3.f), v3(af);

    std::cout << v1 << v2 << v3 << std::endl;
    std::cout << v2 << std::endl;
    std::cout << dot(v2, v3) << std::endl;
    std::cout << (v2 = cross(v2, v3)) << std::endl;
    v1 = cross (v2, v3);
    std::cout << v1 << std::endl;
    std::cout << lengthSq(v2) << std::endl;
    std::cout << length(v2) << std::endl;
    std::cout << normalize(v2) << std::endl;

    std::cout << std::endl;
    float mf[16] = { 1,  2,  3,  4,
                     5,  6,  7,  8,
                     9, 10, 11, 12,
                    13, 14, 15, 16};
    mat4 m1(mf), m2(2);

    std::cout << m1 << std::endl << std::endl << m2 << std::endl << std::endl;
    std::cout << m1 + m2 << std::endl;

    std::cout << -(m1 * -2.f) << std::endl << std::endl;
    std::cout << mat2(3, -5, 2, 4) * vec2(.5, -.25) << std::endl;
    std::cout << vec2(.5, -.25) * mat2(3, -5, 2, 4) << std::endl;
    vec4 v4(-2, 3, -3, 1);
    mat3 m( 1, 2, 3,
            4, 5, 6,
            7, 8, 9);
    std::cout << m << std::endl;
    m[2] = vec3(-1.f, -2.f, -3.f);
    std::cout << m << std::endl;
    m2[2] = v4;
    std::cout << m * transpose(m) << std::endl;
    std::cout << (m[2] = v2) << std::endl;
    std::cout << m << std::endl;

    vec2 b(1, 2);

    std::cout << normalize(b) << std::endl;
    std::cout << std::endl;

    std::cout << (vec3(3, 4, 5) == vec3(4, 4, 4)) << std::endl;
    std::cout << (vec4(3, 4, 5, 1) != vec4(1, 2, 5, 1)) << std::endl;
    std::cout << greaterThanEqual(vec3(3, 4, 5), vec3(1, 7, 5)) << std::endl;
    std::cout << min(vec3(3, 4, 5), vec3(1, 7, 5)) << std::endl;
    std::cout << max(vec3(3, 4, 5), vec3(1, 7, 5)) << std::endl;
    std::cout << lessThan(ivec2(3, 4), ivec2(1, 7)) << std::endl;

    std::cout << std::endl;
    std::cout << mat2(vec2(1, 2), vec2(3, 4)) << std::endl;
    std::cout << mat3(vec3(1, 2, 3), vec3(4, 5, 6), vec3(7, 8, 9)) << std::endl;
    std::cout << mat4(vec4(1, 2, 3, 4), vec4(5, 6, 7, 8), vec4(9, 10, 11, 12), vec4(13, 14, 15, 16)) << std::endl;

    std::cout << std::endl;

    std::cout << distance(vec3(1, 2, 6), vec3(5, -2, 3)) << std::endl;

    std::cout << min(vec3(1, 2, 5), 3.f) << std::endl;
    std::cout << clamp(vec4(4, 3, -2, 1), vec4(-1, -2, -1, -4), vec4(1, 2, 3, 4)) << std::endl;
    std::cout << clamp(vec4(4, 3, -2, 1), -1.f, 1.f) << std::endl;

    std::cout << clamp(m1, 3.f, 8.f) << std::endl;

    std::cout << hadd(vec2(-1, 3)) << std::endl;

    std::cout << hmul(mat3(1, 2, 3, 4, 5, 6, 7, 8, 9)) << std::endl;

    std::cout << hor(ivec3(0, 7, 1)) << std::endl;

    std::cout << "testing min max stuff" << std::endl;
    std::cout << max( vec2(1, 2) ) << std::endl;
    std::cout << max( vec2(2, 1) ) << std::endl;
    std::cout << min( vec2(1, 2) ) << std::endl;
    std::cout << min( vec2(2, 1) ) << std::endl;
    std::cout << max( vec4(1, 2, 3, 4) ) << std::endl;
    std::cout << max( vec4(4, 3, 2, 1) ) << std::endl;
    std::cout << min( vec4(1, 2, 3, 4) ) << std::endl;
    std::cout << min( vec4(4, 3, 2, 1) ) << std::endl;

    plane p1(2, -5, 3, 12), p2(3, 4, -3, 6);
    line3 l;
    p1.intersect(p2, l);
    std::cout << l << std::endl;

    line3 l1(vec3(1, 0, 0), vec3(1, 1, 0)), l2(vec3(2, 0, 0), vec3(2, 1, 0));
    vec3 vIntersect;
    std::cout << l1.intersect(l2, vIntersect) << " " << vIntersect << std::endl;
    l2 = line3(vec3(0, 0, 0), vec3(.5f, .5f, 0));
    std::cout << l1.intersect(l2, vIntersect) << " " << vIntersect << std::endl;

    l1 = line3(vec3(0, 0, 0), vec3(-1, 0, 0));
    p1 = plane(vec3(0.5f, 0, 1), vec3(0.5f, 0, -1), vec3(0.5f, -1, 0));

    float f;
    std::cout << p1.d << " " << p1.n << std::endl;
    std::cout << p1.intersect(l1, f);
    std::cout << " " << f << " " << l1.getFromParam(f) << std::endl;

    std::cout << plane( vec3(0, 0, -1), 2.f).distance( vec3(432, 543, -2.2) ) << std::endl;

    std::cout << plane(1, 2, 3, 4) << std::endl;

    Matrix4<double> md(m1);
    Matrix3<double> m3d( mat3(1, 2, 3, 4, 5, 6, 7, 8, 9) );
    Matrix2<double> m2d( mat2(1, 2, 3, 4) );
    std::cout << m1 << md << m3d << m2d << std::endl;

    mat4 qm = generateMatrixFromQuat( quat(1.f, 0.f, 0.f, 0.25f) );
    mat4 inv;
    bool binvert = qm.invert(inv);
    std::cout << binvert << std::endl;
    std::cout << "\n" << qm << "\n" << generateMatrixFromQuat( quat(1.f, 0.f, 0.f, -0.25f) ) << "\n" <<  inv << std::endl;


    line2 l21 = line2(vec2(2, -3), vec2(-3, -8));
    line2 l22 = line2(vec2(2, -0.5), vec2(-3, -9.5));
    vec2 ip;
    std::cout << l21 << " intersect with " << l22 << ": " << l21.intersect(l22, ip) << std::endl;
    std::cout << ip << std::endl;

    {
        vec3 v(2.3, 4.5, 6.4);
        normalize(v);
        std::cout << ceil(v) << " " << floor(v) << std::endl;
    }

    std::cout << isign(-3.f) << std::endl;
    std::cout << isign(0.f) << std::endl;
    std::cout << isign(3.f) << std::endl;
    std::cout << "---" << std::endl;

    std::cout << ifloor( 3.3) << std::endl;
    std::cout << ifloor( 0.0) << std::endl;
    std::cout << ifloor(-3.3) << std::endl;
    std::cout << "---" << std::endl;

    std::cout << iceil( 3.3) << std::endl;
    std::cout << iceil( 0.0) << std::endl;
    std::cout << iceil(-3.3) << std::endl;
    std::cout << "---" << std::endl;

    std::cout << ifix( 3.3) << std::endl;
    std::cout << ifix( 0.0) << std::endl;
    std::cout << ifix(-3.3) << std::endl;
    std::cout << "---" << std::endl;

    std::cout << iround( 3.3) << std::endl;
    std::cout << iround( 0.0) << std::endl;
    std::cout << iround(-3.3) << std::endl;
    std::cout << "---" << std::endl;

    std::cout << iround( 3.7) << std::endl;
    std::cout << iround( 0.0) << std::endl;
    std::cout << iround(-3.7) << std::endl;

    {
        vec2 v2(-1.3f, 2.8f);
        vec3 v3(-1.6f, 2.2f, 0.f);
        vec4 v4(-1.3f, -1.7f, 2.2f, 2.8f);

        std::cout << isign(v2) << std::endl;
        std::cout << isign(v3) << std::endl;
        std::cout << isign(v4) << std::endl;

        std::cout << iceil(v2) << std::endl;
        std::cout << iceil(v3) << std::endl;
        std::cout << iceil(v4) << std::endl;

        std::cout << ifloor(v2) << std::endl;
        std::cout << ifloor(v3) << std::endl;
        std::cout << ifloor(v4) << std::endl;

        std::cout << iround(v2) << std::endl;
        std::cout << iround(v3) << std::endl;
        std::cout << iround(v4) << std::endl;

        std::cout << ifix(v2) << std::endl;
        std::cout << ifix(v3) << std::endl;
        std::cout << ifix(v4) << std::endl;

    }

    return 0;
}
